package request

import (
	"bytes"
	"errors"
	"fmt"
	"go.manyji.com/lib/config"
	"go.manyji.com/lib/encoding/json"
	"go.manyji.com/lib/log"
	"go.manyji.com/lib/net/socks5"
	"go.manyji.com/lib/net/socks5/socks5http"
	"io"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"net/url"
	"strings"
	"time"
)

var (
	httpClient         *http.Client
	requestSocks5Debug = config.Bool("request.socks5.debug", false, "")
	requestTimeout     = config.Int("request.timeout", 0, "")
)

func init() {
	t := http.DefaultTransport.(*http.Transport).Clone()
	httpClient = &http.Client{
		Timeout:   30 * time.Second,
		Transport: t,
	}
}

type reqResponse struct {
	Code   int
	Data   string
	ErrMsg string
}

func Post(u string, data map[string]string) (string, error) {
	defer log.RecoverPanic()
	values := make(url.Values)
	for k, v := range data {
		values.Add(k, v)
	}
	req, err := http.NewRequest("POST", u, strings.NewReader(values.Encode()))
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	res, err := httpClient.Do(req)
	if err != nil {
		return "", err
	}
	content, err := io.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return "", err
	}
	retData := &reqResponse{}
	err = json.Unmarshal(content, retData)
	if err != nil {
		return "", err
	}
	if retData.Code == 200 {
		return retData.Data, nil
	}
	return "", errors.New(retData.ErrMsg)
}

var (
	_uploadClient *http.Client
)

func initClient() {
	if *requestSocks5Debug {
		_uploadClient = socks5http.NewClient(socks5.New("47.243.62.169:10080", nil))
		_uploadClient.Timeout = time.Duration(*requestTimeout) * time.Second // 请求超时时间
	} else {
		_uploadClient = &http.Client{
			Timeout: time.Duration(*requestTimeout) * time.Second, // 请求超时时间
		}
	}
}
func HttpUploadFile(url string, params map[string]string, filename string, file io.Reader) ([]byte, error) {
	if _uploadClient == nil {
		initClient()
	}
	body := new(bytes.Buffer)
	writer := multipart.NewWriter(body)
	// 在表单中创建一个文件字段
	formFile, err := CreateFormFile(writer, "file", filename)
	if err != nil {
		return nil, err
	}
	// 读取文件内容到表单文件字段
	_, err = io.Copy(formFile, file)
	if err != nil {
		return nil, err
	}
	// 将其他参数写入到表单
	for key, val := range params {
		_ = writer.WriteField(key, val)
	}
	if err = writer.Close(); err != nil {
		return nil, err
	}
	// 构造请求对象
	req, err := http.NewRequest("POST", url, body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", writer.FormDataContentType())
	// 发送请求
	resp, err := _uploadClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	return io.ReadAll(resp.Body)
}

func CreateFormFile(w *multipart.Writer, fieldname, filename string) (io.Writer, error) {
	h := make(textproto.MIMEHeader)
	h.Set("Content-Disposition",
		fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
			fieldname, filename))
	h.Set("Content-Type", "text/plain")
	return w.CreatePart(h)
}

func Get(u string) (string, error) {
	defer log.RecoverPanic()
	u, err := url.QueryUnescape(u)
	if err != nil {
		return "", err
	}
	u = strings.Replace(u, "+", "%20", -1)
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		return "", err
	}
	if _uploadClient == nil {
		initClient()
	}
	res, err := _uploadClient.Do(req)
	if err != nil {
		return "", err
	}
	content, err := io.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return "", err
	}
	return string(content), nil
}
